/*
	Copyright © 2019 by The qTox Project Contributors

	This file is part of qTox, a Qt-based graphical interface for Tox.

	qTox is libre software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	qTox is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with qTox.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "core/toxcall.h"
#include "audio/audio.h"
#include "core/coreav.h"
#include "persistence/settings.h"
#include "video/corevideosource.h"
#include "video/desktopsource.h"

/**
 * @var uint32_t ToxCall::callId
 * @brief Could be a friendNum or groupNum, must uniquely identify the call. Do not modify!
 *
 * @var bool ToxCall::inactive
 * @brief True while we're not participating. (stopped group call, ringing but hasn't started yet,
 * ...)
 *
 * @var bool ToxFriendCall::videoEnabled
 * @brief True if our user asked for a video call, sending and recieving.
 *
 * @var bool ToxFriendCall::nullVideoBitrate
 * @brief True if our video bitrate is zero, i.e. if the device is closed.
 *
 * @var TOXAV_FRIEND_CALL_STATE ToxFriendCall::state
 * @brief State of the peer (not ours!)
 *
 * @var QMap ToxGroupCall::peers
 * @brief Keeps sources for users in group calls.
 */

ToxCall::ToxCall(bool VideoEnabled, CoreAV& av, IAudioControl& audio)
	: av{ &av }
	, audio(audio)
	, videoEnabled{ VideoEnabled }
	, audioSource(audio.makeSource())
{}

ToxCall::~ToxCall()
{
	if (videoEnabled) {
		DesktopSource& source = DesktopSource::getInstance();
		source.frameAvailable.disconnect(frameAvailableConID);
		source.unsubscribe();
	}
}

bool ToxCall::isActive() const
{
	return active;
}

void ToxCall::setActive(bool value)
{
	active = value;
}

bool ToxCall::getMuteVol() const
{
	return muteVol;
}

void ToxCall::setMuteVol(bool value)
{
	muteVol = value;
}

bool ToxCall::getMuteMic() const
{
	return muteMic;
}

void ToxCall::setMuteMic(bool value)
{
	muteMic = value;
}

bool ToxCall::getVideoEnabled() const
{
	return videoEnabled;
}

void ToxCall::setVideoEnabled(bool value)
{
	videoEnabled = value;
}

bool ToxCall::getNullVideoBitrate() const
{
	return nullVideoBitrate;
}

void ToxCall::setNullVideoBitrate(bool value)
{
	nullVideoBitrate = value;
}

CoreVideoSource* ToxCall::getVideoSource() const
{
	return videoSource;
}

ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av, IAudioControl& audio, bool bctrl)
	: ToxCall(VideoEnabled, av, audio)
	, sink(audio.makeSink())
	, friendId{ FriendNum }
{
	//connect(audioSource.get(), &IAudioSource::frameAvailable, this,
	//                     [this](const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) {
	//                         this->av->sendCallAudio(this->friendId, pcm, samples, chans, rate);
	//                     });

   // connect(audioSource.get(), &IAudioSource::invalidated, this, &ToxFriendCall::onAudioSourceInvalidated);

	if (sink) {
		//audioSinkInvalid = sink->connectTo_invalidated(this, [this]() { this->onAudioSinkInvalidated(); });
	}

	// register video
	if (videoEnabled) {
		videoSource = new CoreVideoSource();
		DesktopSource& source = DesktopSource::getInstance();
		if (bctrl) {

			auto models = DesktopSource::getScreenModes();
			if (models.size() > 0) {

				source.setupDevice("", models[0]);
			}

			source.subscribe();
		}

		frameAvailableConID = source.frameAvailable.connect([&av, FriendNum](std::shared_ptr<vpx_image_t> frame) {
			av.sendCallVideo(FriendNum, frame);
		});

	}
}

ToxFriendCall::~ToxFriendCall()
{
	// QObject::disconnect(audioSinkInvalid);
}

void ToxFriendCall::onAudioSourceInvalidated()
{
	auto newSrc = audio.makeSource();
	//connect(newSrc.get(), &IAudioSource::frameAvailable, this,
	//                     [this](const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) {
	//                         this->av->sendCallAudio(this->friendId, pcm, samples, chans, rate);
	//                     });
	audioSource = std::move(newSrc);

	//connect(audioSource.get(), &IAudioSource::invalidated, this, &ToxFriendCall::onAudioSourceInvalidated);
}

void ToxFriendCall::onAudioSinkInvalidated()
{
	auto newSink = audio.makeSink();

	if (newSink) {
		//audioSinkInvalid = newSink->connectTo_invalidated(this, [this]() { this->onAudioSinkInvalidated(); });
	}

	sink = std::move(newSink);
}

TOXAV_FRIEND_CALL_STATE ToxFriendCall::getState() const
{
	return state;
}

void ToxFriendCall::setState(const TOXAV_FRIEND_CALL_STATE& value)
{
	state = value;
}

void ToxFriendCall::playAudioBuffer(const int16_t* data, int samples, unsigned channels,
	int sampleRate) const
{
	if (sink) {
		sink->playAudioBuffer(data, samples, channels, sampleRate);
	}
}